package com.seven.ssa.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.EntryType;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.Tracer;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.seven.ssa.annotation.AuthCheck;
import com.seven.ssa.common.BaseResponse;
import com.seven.ssa.common.DeleteRequest;
import com.seven.ssa.common.ErrorCode;
import com.seven.ssa.common.ResultUtils;
import com.seven.ssa.exception.BusinessException;

import com.seven.ssa.model.dto.question.QuestionAddRequest;
import com.seven.ssa.model.dto.question.QuestionBatchRemoveRequest;
import com.seven.ssa.model.dto.question.QuestionQueryRequest;
import com.seven.ssa.model.dto.question.QuestionUpdateRequest;
import com.seven.ssa.model.dto.questionBank.QuestionBankQueryRequest;
import com.seven.ssa.model.dto.questionBankQuestion.QuestionBankQuestionBatchAddRequest;
import com.seven.ssa.model.dto.questionBankQuestion.QuestionBankQuestionBatchRemoveRequest;
import com.seven.ssa.model.entity.Question;

import com.seven.ssa.model.entity.QuestionBankQuestion;
import com.seven.ssa.model.entity.User;
import com.seven.ssa.model.vo.QuestionBankVO;
import com.seven.ssa.model.vo.QuestionVO;
import com.seven.ssa.service.QuestionBankQuestionService;
import com.seven.ssa.service.QuestionService;
import com.seven.ssa.service.UserService;

import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 题目接口
 */
@RestController
@RequestMapping("/question")
public class QuestionController {
    
    @Resource
    private QuestionService questionService;
    @Resource
    private UserService userService;
    @Resource
    private QuestionBankQuestionService questionBankQuestionService;

    /**
     * 创建题目
     *
     * @param questionAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add")
    @SaCheckRole("admin")
    public BaseResponse<Long> addQuestion(@RequestBody QuestionAddRequest questionAddRequest, HttpServletRequest request) {
        if (questionAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 设置userId列
        questionAddRequest.setUserId(userService.getLoginUser(request).getId());
        Question question = new Question();
        BeanUtils.copyProperties(questionAddRequest, question);
        boolean result = questionService.save(question);
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR);
        }
        return ResultUtils.success(question.getId());
    }

    /**
     * 删除题目
     *
     * @param deleteRequest
     * @param request
     * @return
     */
    @PostMapping("/delete")
    @SaCheckRole("admin")
    public BaseResponse<Boolean> deleteQuestion(@RequestBody DeleteRequest deleteRequest, HttpServletRequest request) {
        if (deleteRequest == null || deleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean b = questionService.removeById(deleteRequest.getId());
        return ResultUtils.success(b);
    }



    /**
     * 更新题目
     *
     * @param questionUpdateRequest
     * @param request
     * @return
     */
    @PostMapping("/update")
    @SaCheckRole("admin")
    public BaseResponse<Boolean> updateQuestion(@RequestBody QuestionUpdateRequest questionUpdateRequest, HttpServletRequest request) {
        if (questionUpdateRequest == null || questionUpdateRequest.getId() == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 设置userId列
        questionUpdateRequest.setUserId(userService.getLoginUser(request).getId());
        Question question = new Question();
        BeanUtils.copyProperties(questionUpdateRequest, question);
        boolean result = questionService.updateById(question);
        return ResultUtils.success(result);
    }

    /**
     * 根据 id 获取题目
     *
     * @param id
     * @param request
     * @return
     */
    @GetMapping("/get")
    @SaCheckRole("admin")
    public BaseResponse<QuestionVO> getQuestionById(Long id, HttpServletRequest request) {
        if (id <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        Question question = questionService.getById(id);
        QuestionVO questionVO = new QuestionVO();
        BeanUtils.copyProperties(question, questionVO);
        return ResultUtils.success(questionVO);
    }

    /**
     * 获取题目列表
     *
     * @param questionQueryRequest
     * @param request
     * @return
     */
    @GetMapping("/list")
    @SaCheckRole("admin")
    public BaseResponse<List<QuestionVO>> listQuestion(QuestionQueryRequest questionQueryRequest, HttpServletRequest request) {
        Question questionQuery = new Question();
        if (questionQueryRequest != null) {
            BeanUtils.copyProperties(questionQueryRequest, questionQuery);
        }
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>(questionQuery);
        List<Question> questionList = questionService.list(queryWrapper);
        List<QuestionVO> questionVOList = questionList.stream().map(question -> {
            QuestionVO questionVO = new QuestionVO();
            BeanUtils.copyProperties(question, questionVO);
            return questionVO;
        }).collect(Collectors.toList());
        return ResultUtils.success(questionVOList);
    }

    /**
     * 分页获取题目列表
     *
     * @param questionQueryRequest
     * @param request
     * @return
     */
    @GetMapping("/list/page")
    @SaCheckRole("admin")
    public BaseResponse<Page<QuestionVO>> listQuestionByPage(QuestionQueryRequest questionQueryRequest, HttpServletRequest request) {
        long current = 1;
        long size = 10;
        Question questionQuery = new Question();
        if (questionQueryRequest != null) {
            BeanUtils.copyProperties(questionQueryRequest, questionQuery);
            current = questionQueryRequest.getCurrent();
            size = questionQueryRequest.getPageSize();
        }
        QueryWrapper<Question> queryWrapper = new QueryWrapper<>(questionQuery);
        Page<Question> questionPage = questionService.page(new Page<>(current, size), queryWrapper);
        Page<QuestionVO> questionVOPage = new PageDTO<>(questionPage.getCurrent(), questionPage.getSize(), questionPage.getTotal());
        List<QuestionVO> questionVOList = questionPage.getRecords().stream().map(question -> {
            QuestionVO questionVO = new QuestionVO();
            BeanUtils.copyProperties(question, questionVO);
            return questionVO;
        }).collect(Collectors.toList());
        questionVOPage.setRecords(questionVOList);
        return ResultUtils.success(questionVOPage);
    }

    /**
     * P2：通过ES搜索题目列表
     * @param questionQueryRequest
     * @param request
     * @return
     */
    @PostMapping("/search/page/vo")
    public BaseResponse<Page<QuestionVO>> searchQuestionByPage(QuestionQueryRequest questionQueryRequest, HttpServletRequest request) {
        Page<Question> questionPage = questionService.searchFromEs(questionQueryRequest);
        Page<QuestionVO> questionVOPage = questionService.getQuestionVOPage(questionPage, request);
        return ResultUtils.success(questionVOPage);
    }

    /**
     * P3：批量往题库中加题目
     * @param questionBankQuestionBatchAddRequest
     * @param request
     * @return
     */
    @PostMapping("/add/batch")
    @SaCheckRole("admin")
    public BaseResponse<Long> addBatchQuestion(
            @RequestBody QuestionBankQuestionBatchAddRequest questionBankQuestionBatchAddRequest,
            HttpServletRequest request) {
        if (questionBankQuestionBatchAddRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 设置userId列
        questionBankQuestionBatchAddRequest.setUserId(userService.getLoginUser(request).getId());
        questionBankQuestionService.batchAddQuestionsToBank(questionBankQuestionBatchAddRequest,request);
        return ResultUtils.success(questionBankQuestionBatchAddRequest.getId());
    }

    /**
     * P3：批量往题库中删题目
     * @param questionBankQuestionBatchRemoveRequest
     * @param request
     * @return
     */
    @PostMapping("/remove/batch")
    @SaCheckRole("admin")
    public BaseResponse<Long> removeBatchQuestion(
            @RequestBody QuestionBankQuestionBatchRemoveRequest questionBankQuestionBatchRemoveRequest,
            HttpServletRequest request) {
        if (questionBankQuestionBatchRemoveRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        // 设置userId列
        questionBankQuestionBatchRemoveRequest.setUserId(userService.getLoginUser(request).getId());
        questionBankQuestionService.batchRemoveQuestionsToBank(questionBankQuestionBatchRemoveRequest,request);
        return ResultUtils.success(questionBankQuestionBatchRemoveRequest.getId());
    }

    /**
     * P3：批量删除题目
     * @param questionBatchRemoveRequest
     * @param request
     * @return
     */
    @PostMapping("/delete/batch")
    @SaCheckRole("admin")
    public BaseResponse<Boolean> batchDeleteQuestion
    (@RequestBody QuestionBatchRemoveRequest questionBatchRemoveRequest, HttpServletRequest request) {
        if(ObjectUtils.anyNull(questionBatchRemoveRequest, questionBatchRemoveRequest.getQuestionIdList())) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR);
        }
        boolean flag = true;
        for(Long questionId : questionBatchRemoveRequest.getQuestionIdList()) {
            if(questionService.getById(questionId) == null) {
                throw new BusinessException(ErrorCode.OPERATION_ERROR,"batchDeleteQuestion有题目id无对应题目！");
            }
            boolean b = questionService.removeById(questionId);
            if(!b) {flag=false;}
            // 对应的库目关系也要跟着删除
            LambdaQueryWrapper<QuestionBankQuestion> lambdaQueryWrapper = Wrappers.lambdaQuery(QuestionBankQuestion.class)
                    .eq(QuestionBankQuestion::getQuestionId, questionId);
            // 进行删除操作
            b = questionBankQuestionService.remove(lambdaQueryWrapper);
            if(!b) {flag=false;}
        }
        return ResultUtils.success(flag);
    }

    /**
     * P7：定义资源
     */
    public BaseResponse<Page<QuestionVO>> resourceDefine(@RequestBody QuestionQueryRequest questionQueryRequest,
                                                             HttpServletRequest request) {
        // 基于 IP 限流
        String remoteAddr = request.getRemoteAddr();
        Entry entry = null;
        try  {
            entry = SphU.entry("listQuestionByPage", EntryType.IN, 1, remoteAddr);
            // 被保护的业务逻辑
            // 查询数据库
            Page<Question> questionPage = questionService.listQuestionByPage(questionQueryRequest);
            // 获取封装类
            return ResultUtils.success(questionService.getQuestionVOPage(questionPage, request));
        } catch (Throwable ex) {
            // 业务异常
            if(!BlockException.isBlockException(ex)){
                Tracer.trace(ex);
                return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统错误");
            }
            // 降级操作
            if (ex instanceof DegradeException) {
                return handleFallback(questionQueryRequest, request, ex);
            }
            // 限流操作
            return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "访问过于频繁，请稍后再试");
        } finally {
            if (entry != null) {
                entry.exit(1, remoteAddr);
            }
        }
    }
    /**
     * P7：降级操作：直接返回本地数据（对应@SentinelResource注解）
     */
    public BaseResponse<Page<QuestionVO>> handleFallback(@RequestBody QuestionQueryRequest questionQueryRequest,
                                                             HttpServletRequest request, Throwable ex) {
        // 可以返回本地数据或空数据
        return ResultUtils.success(null);
    }

    /**
     * P7：限流操作：提示“系统压力过大，请耐心等待”（对应@SentinelResource注解）
     */
    public BaseResponse<Page<QuestionVO>> handleBlockException(@RequestBody QuestionQueryRequest questionQueryRequest,
                                                                   HttpServletRequest request, BlockException ex) {
        // 降级操作
        if(ex instanceof DegradeException) {
            return handleFallback(questionQueryRequest, request, ex);
        }
        // 限流操作
        return ResultUtils.error(ErrorCode.SYSTEM_ERROR, "系统压力过大，请耐心等待");
    }
}
